{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "sZVlYSmRjzuk"
   },
   "source": [
    "# Tutorial: Classifying Documents & Queries by Language\n",
    "\n",
    "- **Level**: Beginner\n",
    "- **Time to complete**: 15 minutes\n",
    "- **Components Used**: [`InMemoryDocumentStore`](https://docs.haystack.deepset.ai/docs/inmemorydocumentstore), [`DocumentLanguageClassifier`](https://docs.haystack.deepset.ai/docs/documentlanguageclassifier), [`MetadataRouter`](https://docs.haystack.deepset.ai/docs/metadatarouter), [`DocumentWriter`](https://docs.haystack.deepset.ai/docs/documentwriter), [`TextLanguageRouter`](https://docs.haystack.deepset.ai/docs/textlanguagerouter), [`DocumentJoiner`](https://docs.haystack.deepset.ai/docs/documentjoiner), [`InMemoryBM25Retriever`](https://docs.haystack.deepset.ai/docs/inmemorybm25retriever), [`PromptBuilder`](https://docs.haystack.deepset.ai/docs/promptbuilder), [`OpenAIGenerator`](https://docs.haystack.deepset.ai/docs/openaigenerator)\n",
    "- **Goal**: After completing this tutorial, you'll have learned how to build a Haystack pipeline to classify documents based on the (human) language they were written in.\n",
    "- Optionally, at the end you'll also incorporate language clasification and query routing into a RAG pipeline, so you can query documents based on the language a question was written in.\n",
    "\n",
    "> This tutorial uses Haystack 2.0. To learn more, read the [Haystack 2.0 announcement](https://haystack.deepset.ai/blog/haystack-2-release) or visit the [Haystack 2.0 Documentation](https://docs.haystack.deepset.ai/docs/intro).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "G8qw1k7nf7yH"
   },
   "source": [
    "## Overview\n",
    "\n",
    "In a gobalized society with over 7,000 human languages spoken worldwide today, handling multilingual input is a common use case for NLP applications.\n",
    "\n",
    "Good news: Haystack has a [`DocumentLanguageClassifier`](https://docs.haystack.deepset.ai/docs/documentlanguageclassifier) built in. This component detects the language a document was written in. This functionality lets you create *branches* in your Haystack pipelines, granting the flexibility to add different processing steps for each language. For example, you could use a LLM that performs better in German to answer German queries. Or, you could fetch only French restaurant reviews for your French users.\n",
    "\n",
    "In this tutorial, you'll take a text samples from hotel reviews, written in different languages. The text samples will be made into Haystack documents and classified by language. Then each document will be written to a language-specific `DocumentStore`. To validate that the language detection is working correctly, you'll filter the document stores to display their contents.\n",
    "\n",
    "In the last section, you'll build a multi-lingual RAG pipeline. The language of a question is detected, and only documents in that language are used to generate the answer. For this section, the [`TextLanguageRouter`](https://docs.haystack.deepset.ai/docs/textlanguagerouter) will come in handy.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "oBa4Q25cGTr6"
   },
   "source": [
    "## Preparing the Colab Environment\n",
    "\n",
    "- [Enable GPU Runtime in Colab](https://docs.haystack.deepset.ai/docs/enabling-gpu-acceleration)\n",
    "- [Set logging level to INFO](https://docs.haystack.deepset.ai/docs/logging)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "oC7ff5x0XTfN"
   },
   "source": [
    "# Installing Haystack\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "lxgAfuxcdftS",
    "outputId": "36339d6b-f7a8-4686-911a-60642a8adbe6"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting haystack-ai\n",
      "  Using cached haystack_ai-2.5.1-py3-none-any.whl.metadata (13 kB)\n",
      "Collecting haystack-experimental (from haystack-ai)\n",
      "  Using cached haystack_experimental-0.1.1-py3-none-any.whl.metadata (6.9 kB)\n",
      "Requirement already satisfied: jinja2 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (3.1.4)\n",
      "Collecting lazy-imports (from haystack-ai)\n",
      "  Using cached lazy_imports-0.3.1-py3-none-any.whl.metadata (10 kB)\n",
      "Collecting more-itertools (from haystack-ai)\n",
      "  Downloading more_itertools-10.5.0-py3-none-any.whl.metadata (36 kB)\n",
      "Collecting networkx (from haystack-ai)\n",
      "  Using cached networkx-3.3-py3-none-any.whl.metadata (5.1 kB)\n",
      "Collecting numpy<2 (from haystack-ai)\n",
      "  Using cached numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl.metadata (61 kB)\n",
      "Collecting openai>=1.1.0 (from haystack-ai)\n",
      "  Downloading openai-1.45.0-py3-none-any.whl.metadata (22 kB)\n",
      "Collecting pandas (from haystack-ai)\n",
      "  Using cached pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl.metadata (19 kB)\n",
      "Collecting posthog (from haystack-ai)\n",
      "  Downloading posthog-3.6.5-py2.py3-none-any.whl.metadata (2.0 kB)\n",
      "Requirement already satisfied: python-dateutil in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (2.9.0)\n",
      "Requirement already satisfied: pyyaml in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (6.0.1)\n",
      "Requirement already satisfied: requests in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (2.32.3)\n",
      "Collecting tenacity!=8.4.0 (from haystack-ai)\n",
      "  Using cached tenacity-9.0.0-py3-none-any.whl.metadata (1.2 kB)\n",
      "Collecting tqdm (from haystack-ai)\n",
      "  Using cached tqdm-4.66.5-py3-none-any.whl.metadata (57 kB)\n",
      "Requirement already satisfied: typing-extensions>=4.7 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from haystack-ai) (4.12.2)\n",
      "Collecting anyio<5,>=3.5.0 (from openai>=1.1.0->haystack-ai)\n",
      "  Using cached anyio-4.4.0-py3-none-any.whl.metadata (4.6 kB)\n",
      "Collecting distro<2,>=1.7.0 (from openai>=1.1.0->haystack-ai)\n",
      "  Using cached distro-1.9.0-py3-none-any.whl.metadata (6.8 kB)\n",
      "Collecting httpx<1,>=0.23.0 (from openai>=1.1.0->haystack-ai)\n",
      "  Downloading httpx-0.27.2-py3-none-any.whl.metadata (7.1 kB)\n",
      "Collecting jiter<1,>=0.4.0 (from openai>=1.1.0->haystack-ai)\n",
      "  Using cached jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl.metadata (3.6 kB)\n",
      "Collecting pydantic<3,>=1.9.0 (from openai>=1.1.0->haystack-ai)\n",
      "  Downloading pydantic-2.9.1-py3-none-any.whl.metadata (146 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m147.0/147.0 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hCollecting sniffio (from openai>=1.1.0->haystack-ai)\n",
      "  Using cached sniffio-1.3.1-py3-none-any.whl.metadata (3.9 kB)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from jinja2->haystack-ai) (2.1.5)\n",
      "Collecting pytz>=2020.1 (from pandas->haystack-ai)\n",
      "  Downloading pytz-2024.2-py2.py3-none-any.whl.metadata (22 kB)\n",
      "Collecting tzdata>=2022.7 (from pandas->haystack-ai)\n",
      "  Using cached tzdata-2024.1-py2.py3-none-any.whl.metadata (1.4 kB)\n",
      "Requirement already satisfied: six>=1.5 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from python-dateutil->haystack-ai) (1.16.0)\n",
      "Collecting monotonic>=1.5 (from posthog->haystack-ai)\n",
      "  Using cached monotonic-1.6-py2.py3-none-any.whl.metadata (1.5 kB)\n",
      "Collecting backoff>=1.10.0 (from posthog->haystack-ai)\n",
      "  Using cached backoff-2.2.1-py3-none-any.whl.metadata (14 kB)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests->haystack-ai) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests->haystack-ai) (3.7)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests->haystack-ai) (2.2.2)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from requests->haystack-ai) (2024.6.2)\n",
      "Collecting httpcore==1.* (from httpx<1,>=0.23.0->openai>=1.1.0->haystack-ai)\n",
      "  Using cached httpcore-1.0.5-py3-none-any.whl.metadata (20 kB)\n",
      "Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx<1,>=0.23.0->openai>=1.1.0->haystack-ai)\n",
      "  Using cached h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)\n",
      "Collecting annotated-types>=0.6.0 (from pydantic<3,>=1.9.0->openai>=1.1.0->haystack-ai)\n",
      "  Using cached annotated_types-0.7.0-py3-none-any.whl.metadata (15 kB)\n",
      "Collecting pydantic-core==2.23.3 (from pydantic<3,>=1.9.0->openai>=1.1.0->haystack-ai)\n",
      "  Downloading pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl.metadata (6.6 kB)\n",
      "Using cached haystack_ai-2.5.1-py3-none-any.whl (351 kB)\n",
      "Using cached numpy-1.26.4-cp312-cp312-macosx_10_9_x86_64.whl (20.3 MB)\n",
      "Downloading openai-1.45.0-py3-none-any.whl (374 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m374.1/374.1 kB\u001b[0m \u001b[31m12.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hUsing cached tenacity-9.0.0-py3-none-any.whl (28 kB)\n",
      "Using cached tqdm-4.66.5-py3-none-any.whl (78 kB)\n",
      "Using cached haystack_experimental-0.1.1-py3-none-any.whl (41 kB)\n",
      "Using cached lazy_imports-0.3.1-py3-none-any.whl (12 kB)\n",
      "Downloading more_itertools-10.5.0-py3-none-any.whl (60 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m61.0/61.0 kB\u001b[0m \u001b[31m4.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hUsing cached networkx-3.3-py3-none-any.whl (1.7 MB)\n",
      "Using cached pandas-2.2.2-cp312-cp312-macosx_10_9_x86_64.whl (12.5 MB)\n",
      "Downloading posthog-3.6.5-py2.py3-none-any.whl (54 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m54.2/54.2 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hUsing cached anyio-4.4.0-py3-none-any.whl (86 kB)\n",
      "Using cached backoff-2.2.1-py3-none-any.whl (15 kB)\n",
      "Using cached distro-1.9.0-py3-none-any.whl (20 kB)\n",
      "Downloading httpx-0.27.2-py3-none-any.whl (76 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.4/76.4 kB\u001b[0m \u001b[31m6.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hUsing cached httpcore-1.0.5-py3-none-any.whl (77 kB)\n",
      "Using cached jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl (283 kB)\n",
      "Using cached monotonic-1.6-py2.py3-none-any.whl (8.2 kB)\n",
      "Downloading pydantic-2.9.1-py3-none-any.whl (434 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m434.4/434.4 kB\u001b[0m \u001b[31m7.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hDownloading pydantic_core-2.23.3-cp312-cp312-macosx_10_12_x86_64.whl (1.8 MB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.8/1.8 MB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m00:01\u001b[0m00:01\u001b[0mm\n",
      "\u001b[?25hDownloading pytz-2024.2-py2.py3-none-any.whl (508 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m508.0/508.0 kB\u001b[0m \u001b[31m10.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0ma \u001b[36m0:00:01\u001b[0m\n",
      "\u001b[?25hUsing cached sniffio-1.3.1-py3-none-any.whl (10 kB)\n",
      "Using cached tzdata-2024.1-py2.py3-none-any.whl (345 kB)\n",
      "Using cached annotated_types-0.7.0-py3-none-any.whl (13 kB)\n",
      "Using cached h11-0.14.0-py3-none-any.whl (58 kB)\n",
      "Installing collected packages: pytz, monotonic, tzdata, tqdm, tenacity, sniffio, pydantic-core, numpy, networkx, more-itertools, lazy-imports, jiter, h11, distro, backoff, annotated-types, pydantic, posthog, pandas, httpcore, anyio, httpx, openai, haystack-experimental, haystack-ai\n",
      "Successfully installed annotated-types-0.7.0 anyio-4.4.0 backoff-2.2.1 distro-1.9.0 h11-0.14.0 haystack-ai-2.5.1 haystack-experimental-0.1.1 httpcore-1.0.5 httpx-0.27.2 jiter-0.5.0 lazy-imports-0.3.1 monotonic-1.6 more-itertools-10.5.0 networkx-3.3 numpy-1.26.4 openai-1.45.0 pandas-2.2.2 posthog-3.6.5 pydantic-2.9.1 pydantic-core-2.23.3 pytz-2024.2 sniffio-1.3.1 tenacity-9.0.0 tqdm-4.66.5 tzdata-2024.1\n",
      "Collecting langdetect\n",
      "  Using cached langdetect-1.0.9-py3-none-any.whl\n",
      "Requirement already satisfied: six in /Users/tuanacelik/opt/anaconda3/envs/tutorials/lib/python3.12/site-packages (from langdetect) (1.16.0)\n",
      "Installing collected packages: langdetect\n",
      "Successfully installed langdetect-1.0.9\n"
     ]
    }
   ],
   "source": [
    "%%bash\n",
    "\n",
    "pip install haystack-ai\n",
    "pip install langdetect"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "32oB-HJlGXmY"
   },
   "source": [
    "### Enabling Telemetry\n",
    "\n",
    "Knowing you're using this tutorial helps us decide where to invest our efforts to build a better product but you can always opt out by commenting the following line. See [Telemetry](https://docs.haystack.deepset.ai/docs/enabling-telemetry) for more details."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "Ubr7yVt6Gbnj"
   },
   "outputs": [],
   "source": [
    "from haystack.telemetry import tutorial_running\n",
    "\n",
    "tutorial_running(32)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "K0wRwkyvkV3Z"
   },
   "source": [
    "## Write Documents Into `InMemoryDocumentStore`\n",
    "\n",
    "The following indexing pipeline writes French and English documents into their own `InMemoryDocumentStores` based on language.\n",
    "\n",
    "Import the modules you'll need. Then instantiate a list of Haystack `Documents` that are snippets of hotel reviews in various languages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "mN2fFuWWP_8D"
   },
   "outputs": [],
   "source": [
    "from haystack import Document, Pipeline\n",
    "from haystack.document_stores.in_memory import InMemoryDocumentStore\n",
    "from haystack.components.classifiers import DocumentLanguageClassifier\n",
    "from haystack.components.routers import MetadataRouter\n",
    "from haystack.components.writers import DocumentWriter\n",
    "\n",
    "\n",
    "documents = [\n",
    "    Document(\n",
    "        content=\"Super appartement. Juste au dessus de plusieurs bars qui ferment très tard. A savoir à l'avance. (Bouchons d'oreilles fournis !)\"\n",
    "    ),\n",
    "    Document(\n",
    "        content=\"El apartamento estaba genial y muy céntrico, todo a mano. Al lado de la librería Lello y De la Torre de los clérigos. Está situado en una zona de marcha, así que si vais en fin de semana , habrá ruido, aunque a nosotros no nos molestaba para dormir\"\n",
    "    ),\n",
    "    Document(\n",
    "        content=\"The keypad with a code is convenient and the location is convenient. Basically everything else, very noisy, wi-fi didn't work, check-in person didn't explain anything about facilities, shower head was broken, there's no cleaning and everything else one may need is charged.\"\n",
    "    ),\n",
    "    Document(\n",
    "        content=\"It is very central and appartement has a nice appearance (even though a lot IKEA stuff), *W A R N I N G** the appartement presents itself as a elegant and as a place to relax, very wrong place to relax - you cannot sleep in this appartement, even the beds are vibrating from the bass of the clubs in the same building - you get ear plugs from the hotel -> now I understand why -> I missed a trip as it was so loud and I could not hear the alarm next day due to the ear plugs.- there is a green light indicating 'emergency exit' just above the bed, which shines very bright at night - during the arrival process, you felt the urge of the agent to leave as soon as possible. - try to go to 'RVA clerigos appartements' -> same price, super quiet, beautiful, city center and very nice staff (not an agency)- you are basically sleeping next to the fridge, which makes a lot of noise, when the compressor is running -> had to switch it off - but then had no cool food and drinks. - the bed was somehow broken down - the wooden part behind the bed was almost falling appart and some hooks were broken before- when the neighbour room is cooking you hear the fan very loud. I initially thought that I somehow activated the kitchen fan\"\n",
    "    ),\n",
    "    Document(content=\"Un peu salé surtout le sol. Manque de service et de souplesse\"),\n",
    "    Document(\n",
    "        content=\"Nous avons passé un séjour formidable. Merci aux personnes , le bonjours à Ricardo notre taxi man, très sympathique. Je pense refaire un séjour parmi vous, après le confinement, tout était parfait, surtout leur gentillesse, aucune chaude négative. Je n'ai rien à redire de négative, Ils étaient a notre écoute, un gentil message tout les matins, pour nous demander si nous avions besoins de renseignement et savoir si tout allait bien pendant notre séjour.\"\n",
    "    ),\n",
    "    Document(\n",
    "        content=\"Céntrico. Muy cómodo para moverse y ver Oporto. Edificio con terraza propia en la última planta. Todo reformado y nuevo. Te traen un estupendo desayuno todas las mañanas al apartamento. Solo que se puede escuchar algo de ruido de la calle a primeras horas de la noche. Es un zona de ocio nocturno. Pero respetan los horarios.\"\n",
    "    ),\n",
    "]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "TcZbAvjbRJLA"
   },
   "source": [
    "Each language gets its own `DocumentStore`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "id": "rfC1ZCigQJgI"
   },
   "outputs": [],
   "source": [
    "en_document_store = InMemoryDocumentStore()\n",
    "fr_document_store = InMemoryDocumentStore()\n",
    "es_document_store = InMemoryDocumentStore()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "d9fyP-ThRTue"
   },
   "source": [
    "The `DocumentLanguageClassifier` takes a list of languages. The `MetadataRouter` needs a dictionary of rules.  These rules specify which node to route a document to (in this case, which language-specific `DocumentWriter`), based on the document's metadata.\n",
    "\n",
    "The keys of the dictionary are the names of the output connections, and the values are dictionaries that follow the format of [filtering expressions in Haystack.](https://docs.haystack.deepset.ai/docs/metadata-filtering).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "id": "FlqGdbuxQNKk"
   },
   "outputs": [],
   "source": [
    "language_classifier = DocumentLanguageClassifier(languages=[\"en\", \"fr\", \"es\"])\n",
    "router_rules = {\"en\": {\"field\": \"meta.language\", \"operator\": \"==\", \"value\": \"en\"}, \n",
    "                \"fr\": {\"field\": \"meta.language\", \"operator\": \"==\", \"value\": \"fe\"}, \n",
    "                \"es\": {\"field\": \"meta.language\", \"operator\": \"==\", \"value\": \"es\"}}\n",
    "router = MetadataRouter(rules=router_rules)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "id": "FEw5pfmBQRBB"
   },
   "outputs": [],
   "source": [
    "en_writer = DocumentWriter(document_store=en_document_store)\n",
    "fr_writer = DocumentWriter(document_store=fr_document_store)\n",
    "es_writer = DocumentWriter(document_store=es_document_store)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "kAQvRdtESq_J"
   },
   "source": [
    "Now that all the components have been created, instantiate the `Pipeline`. Add the components to the pipeline. Connect the outputs of one component to the input of the following component."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "id": "BdvO_fEfcVAY"
   },
   "outputs": [],
   "source": [
    "indexing_pipeline = Pipeline()\n",
    "indexing_pipeline.add_component(instance=language_classifier, name=\"language_classifier\")\n",
    "indexing_pipeline.add_component(instance=router, name=\"router\")\n",
    "indexing_pipeline.add_component(instance=en_writer, name=\"en_writer\")\n",
    "indexing_pipeline.add_component(instance=fr_writer, name=\"fr_writer\")\n",
    "indexing_pipeline.add_component(instance=es_writer, name=\"es_writer\")\n",
    "\n",
    "\n",
    "indexing_pipeline.connect(\"language_classifier\", \"router\")\n",
    "indexing_pipeline.connect(\"router.en\", \"en_writer\")\n",
    "indexing_pipeline.connect(\"router.fr\", \"fr_writer\")\n",
    "indexing_pipeline.connect(\"router.es\", \"es_writer\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ulAiCB1vTIbr"
   },
   "source": [
    "Draw a diagram of the pipeline to see what the graph looks like."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "id": "598ZTa7RzNeR"
   },
   "outputs": [],
   "source": [
    "indexing_pipeline.draw(\"indexing_pipeline.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "UzQX7zFLS_Bk"
   },
   "source": [
    "Run the pipeline and it will tell you how many documents were written in each language. Voila!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "lE5XE8cPXN5-",
    "outputId": "43017d9b-65f8-48ad-dadb-66ad0de3af43"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'router': {'unmatched': []},\n",
       " 'en_writer': {'documents_written': 2},\n",
       " 'fr_writer': {'documents_written': 3},\n",
       " 'es_writer': {'documents_written': 2}}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indexing_pipeline.run(data={\"language_classifier\": {\"documents\": documents}})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "R-Q2SxDnu3v-"
   },
   "source": [
    "### Check the Contents of Your Document Stores\n",
    "\n",
    "You can check the contents of your document stores. Each one should only contain documents in the correct language."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "LNHzxz52uxZV",
    "outputId": "d0459677-73c0-4bb6-f5d3-87c0c00b1552"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "English documents:  [Document(id=8f64ab234c6a5d5652d02bed144d069ec6e988903b071d16fffbf400abfc1047, content: 'The keypad with a code is convenient and the location is convenient. Basically everything else, very...', meta: {'language': 'en'}), Document(id=d4d878288efba5e28a43ae0195e43dadd0298fe36d3d9b3075c5c5120d27763e, content: 'It is very central and appartement has a nice appearance (even though a lot IKEA stuff), *W A R N I ...', meta: {'language': 'en'})]\n",
      "French documents:  [Document(id=ea7ea338874232de2d8105a258813f50345db82772e21ad2c4549dbb7adce8a3, content: 'Super appartement. Juste au dessus de plusieurs bars qui ferment très tard. A savoir à l'avance. (Bo...', meta: {'language': 'fr'}), Document(id=6b64c8a60543ee32b81cd39bc8d6e09fae4bff1b22c6ccdcf414db26fa354e7a, content: 'Un peu salé surtout le sol. Manque de service et de souplesse', meta: {'language': 'fr'}), Document(id=b1be23526f19a8af80a190e775bfd05e65878e585529037cb45b47267a4eaa98, content: 'Nous avons passé un séjour formidable. Merci aux personnes , le bonjours à Ricardo notre taxi man, t...', meta: {'language': 'fr'})]\n",
      "Spanish documents:  [Document(id=72b094c163b22a660528bc5adbdf0fecf96b4b4d753c1b117f15dba482d2f948, content: 'El apartamento estaba genial y muy céntrico, todo a mano. Al lado de la librería Lello y De la Torre...', meta: {'language': 'es'}), Document(id=4b37b8bdfffccfb3211ea167b4fdc5121ca51fc5f869b4f834e8da473f0d3353, content: 'Céntrico. Muy cómodo para moverse y ver Oporto. Edificio con terraza propia en la última planta. Tod...', meta: {'language': 'es'})]\n"
     ]
    }
   ],
   "source": [
    "print(\"English documents: \", en_document_store.filter_documents())\n",
    "print(\"French documents: \", fr_document_store.filter_documents())\n",
    "print(\"Spanish documents: \", es_document_store.filter_documents())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "A6J0ac9UWdrT"
   },
   "source": [
    "## (Optional) Create a Multi-Lingual RAG pipeline\n",
    "\n",
    "To build a multi-lingual RAG pipeline, you can use the[`TextLanguageRouter`](https://docs.haystack.deepset.ai/docs/textlanguagerouter) to detect the language of the query. Then, fetch documents in that same language from the correct `DocumentStore`.\n",
    "\n",
    "In order to do this you'll need an [OpenAI access token](https://help.openai.com/en/articles/4936850-where-do-i-find-my-api-key), although this approach would also work with any other [generator Haystack supports](https://docs.haystack.deepset.ai/docs/generators)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "hVJaARodWezy",
    "outputId": "d9bdcb42-bd50-4fd9-f4d8-a69e8b4b64f8"
   },
   "outputs": [],
   "source": [
    "import os\n",
    "from getpass import getpass\n",
    "\n",
    "if \"OPENAI_API_KEY\" not in os.environ:\n",
    "    os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter OpenAI API key:\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Ei8up-k3qOC4"
   },
   "source": [
    "Let's assume that all these reviews we put in our document stores earlier are for the same accommodation. A RAG pipeline will let you query for information about that apartment, in the language you choose.\n",
    "\n",
    "Import the components you'll need for a RAG pipeline. Write a prompt that will be passed to our LLM, along with the relevant documents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "id": "CN1N2sn1yUVx"
   },
   "outputs": [],
   "source": [
    "from haystack.components.retrievers.in_memory import InMemoryBM25Retriever\n",
    "from haystack.components.joiners import DocumentJoiner\n",
    "from haystack.components.builders import PromptBuilder\n",
    "from haystack.components.generators import OpenAIGenerator\n",
    "from haystack.components.routers import TextLanguageRouter\n",
    "\n",
    "prompt_template = \"\"\"\n",
    "You will be provided with reviews for an accommodation.\n",
    "Answer the question concisely based solely on the given reviews.\n",
    "Reviews:\n",
    "  {% for doc in documents %}\n",
    "    {{ doc.content }}\n",
    "  {% endfor %}\n",
    "Question: {{ query}}\n",
    "Answer:\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "WTCT6u4cz_z6"
   },
   "source": [
    "### Build the Pipeline\n",
    "\n",
    "Create a new `Pipeline`. Add the following components:\n",
    "- `TextLanguageRouter`\n",
    "- `InMemoryBM25Retriever`. You'll need a retriever per language, since each language has its own `DocumentStore`.\n",
    "- `DocumentJoiner`\n",
    "- `PromptBuilder`\n",
    "- `OpenAIGenerator`\n",
    "\n",
    "> Note: The `BM25Retriever` essentially does keyword matching, which isn't as accurate as other search methods. In order to make the LLM responses more precise, you could refacctor your piplines to use an [`EmbeddingRetriever`](https://docs.haystack.deepset.ai/docs/inmemoryembeddingretriever) which performs vector search over the documents."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "id": "BN1Hr_BjWKcl"
   },
   "outputs": [],
   "source": [
    "rag_pipeline = Pipeline()\n",
    "rag_pipeline.add_component(instance=TextLanguageRouter([\"en\", \"fr\", \"es\"]), name=\"router\")\n",
    "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=en_document_store), name=\"en_retriever\")\n",
    "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=fr_document_store), name=\"fr_retriever\")\n",
    "rag_pipeline.add_component(instance=InMemoryBM25Retriever(document_store=es_document_store), name=\"es_retriever\")\n",
    "rag_pipeline.add_component(instance=DocumentJoiner(), name=\"joiner\")\n",
    "rag_pipeline.add_component(instance=PromptBuilder(template=prompt_template), name=\"prompt_builder\")\n",
    "rag_pipeline.add_component(instance=OpenAIGenerator(), name=\"llm\")\n",
    "\n",
    "\n",
    "rag_pipeline.connect(\"router.en\", \"en_retriever.query\")\n",
    "rag_pipeline.connect(\"router.fr\", \"fr_retriever.query\")\n",
    "rag_pipeline.connect(\"router.es\", \"es_retriever.query\")\n",
    "rag_pipeline.connect(\"en_retriever\", \"joiner\")\n",
    "rag_pipeline.connect(\"fr_retriever\", \"joiner\")\n",
    "rag_pipeline.connect(\"es_retriever\", \"joiner\")\n",
    "rag_pipeline.connect(\"joiner.documents\", \"prompt_builder.documents\")\n",
    "rag_pipeline.connect(\"prompt_builder\", \"llm\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "q1C5GHK_1Kkk"
   },
   "source": [
    "You can draw this pipeline and compare the architecture to the `indexing_pipeline` diagram we created earlier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 1000
    },
    "id": "HAFTD5nt1L9a",
    "outputId": "90cbf82b-8fe5-439d-b099-08510e1c1098"
   },
   "outputs": [],
   "source": [
    "rag_pipeline.draw(\"rag_pipeline.png\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-Vr8MbGrEHZV"
   },
   "source": [
    "Try it out by asking a question."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 49,
     "referenced_widgets": [
      "8a6b993b2fbd4537a1f130adc08f2eb0",
      "cbe44862bf474ff692a359314a7c21f1",
      "04daef6e8b9e4779bbe41dc32f4e9083",
      "e5d659cdfd64477bbb9ce80aed7924f8",
      "d8777b76fb5341869afcb084e91231ee",
      "00a38829bf664b0084b5ec704047f00d",
      "f32af41f2b9543e497989b2c44e9d62d",
      "4ffb8a24b1a74cb8be55af79261e65ab",
      "28e5a76ec5b448c7b2d339913fb721c6",
      "d5d73be36bdb4ddb8fcd92f1ae7a2856",
      "f403167cb47840a3b0c796ae4c304401"
     ]
    },
    "id": "wj24fjXN0l6v",
    "outputId": "3c1eed33-c31c-4b72-bcda-fdd64744560b"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Ranking by BM25...: 100%|██████████| 2/2 [00:00<00:00, 3134.76 docs/s]"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "en_question = \"Is this apartment conveniently located?\"\n",
    "\n",
    "result = rag_pipeline.run({\"router\": {\"text\": en_question}, \"prompt_builder\": {\"query\": en_question}})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "i-2P5oqMeUmC",
    "outputId": "8151923f-bbb1-4e6a-fe4e-08c0d7cfcd49"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Yes, the apartment is conveniently located.\n"
     ]
    }
   ],
   "source": [
    "print(result[\"llm\"][\"replies\"][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "U4ChKAl1EKni"
   },
   "source": [
    "How does the pipeline perform en español?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 49,
     "referenced_widgets": [
      "cb611c28471e487a8c53a7af8d0f7ae7",
      "c3876ec6082f466c89d14ea2dccd8207",
      "f4f835630d074a618f4389c69d1a75d2",
      "713bf7f3026f4a1daa52df12016caf82",
      "ae4725f43a3846acbdcbbf79f51166d0",
      "f0ff1b09bbc34065961a09ee894207bd",
      "d58eb54b8b04455b9e506598491b5b2b",
      "3115ad83af834fe4b4fa12362205d98c",
      "34c2218b0a4d4ba486530aeac007b00a",
      "dbdbd1d389d74c06acd9a1d3066c82dc",
      "7b62bd3498bb49ec9e1db68ca088e7ae"
     ]
    },
    "id": "B4_Be1bs1jxJ",
    "outputId": "0b96cf29-d633-4c9b-f54c-a785e1c2cbe4"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Ranking by BM25...: 100%|██████████| 2/2 [00:00<00:00, 15887.52 docs/s]\n"
     ]
    }
   ],
   "source": [
    "es_question = \"¿El desayuno es genial?\"\n",
    "\n",
    "result = rag_pipeline.run({\"router\": {\"text\": es_question}, \"prompt_builder\": {\"query\": es_question}})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "w_1wibY61sjk",
    "outputId": "54f7506e-9af1-42b8-c0c9-cd13fb4cd9eb"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "No, el desayuno no es genial.\n"
     ]
    }
   ],
   "source": [
    "print(result[\"llm\"][\"replies\"][0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "IhHIJYjbTpAw"
   },
   "source": [
    "## What's next\n",
    "\n",
    "If you've been following along, now you know how to incorporate language detection into query and indexing Haystack piplines. Go forth and build the international application of your dreams. 🗺️\n",
    "\n",
    "\n",
    "If you liked this tutorial, there's more to learn about Haystack 2.0:\n",
    "- [Serializing Haystack Pipelines](https://haystack.deepset.ai/tutorials/29_serializing_pipelines)\n",
    "-  [Generating Structured Output with Loop-Based Auto-Correction](https://haystack.deepset.ai/tutorials/28_structured_output_with_loop)\n",
    "- [Preprocessing Different File Types](https://haystack.deepset.ai/tutorials/30_file_type_preprocessing_index_pipeline)\n",
    "\n",
    "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates)."
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "gpuType": "T4",
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  },
  "widgets": {
   "application/vnd.jupyter.widget-state+json": {
    "00a38829bf664b0084b5ec704047f00d": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "04daef6e8b9e4779bbe41dc32f4e9083": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "FloatProgressModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_4ffb8a24b1a74cb8be55af79261e65ab",
      "max": 2,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_28e5a76ec5b448c7b2d339913fb721c6",
      "value": 2
     }
    },
    "28e5a76ec5b448c7b2d339913fb721c6": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ProgressStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "3115ad83af834fe4b4fa12362205d98c": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "34c2218b0a4d4ba486530aeac007b00a": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "ProgressStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "ProgressStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "bar_color": null,
      "description_width": ""
     }
    },
    "4ffb8a24b1a74cb8be55af79261e65ab": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "713bf7f3026f4a1daa52df12016caf82": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_dbdbd1d389d74c06acd9a1d3066c82dc",
      "placeholder": "​",
      "style": "IPY_MODEL_7b62bd3498bb49ec9e1db68ca088e7ae",
      "value": " 2/2 [00:00&lt;00:00, 108.06 docs/s]"
     }
    },
    "7b62bd3498bb49ec9e1db68ca088e7ae": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "8a6b993b2fbd4537a1f130adc08f2eb0": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HBoxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_cbe44862bf474ff692a359314a7c21f1",
       "IPY_MODEL_04daef6e8b9e4779bbe41dc32f4e9083",
       "IPY_MODEL_e5d659cdfd64477bbb9ce80aed7924f8"
      ],
      "layout": "IPY_MODEL_d8777b76fb5341869afcb084e91231ee"
     }
    },
    "ae4725f43a3846acbdcbbf79f51166d0": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "c3876ec6082f466c89d14ea2dccd8207": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_f0ff1b09bbc34065961a09ee894207bd",
      "placeholder": "​",
      "style": "IPY_MODEL_d58eb54b8b04455b9e506598491b5b2b",
      "value": "Ranking by BM25...: 100%"
     }
    },
    "cb611c28471e487a8c53a7af8d0f7ae7": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HBoxModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HBoxModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HBoxView",
      "box_style": "",
      "children": [
       "IPY_MODEL_c3876ec6082f466c89d14ea2dccd8207",
       "IPY_MODEL_f4f835630d074a618f4389c69d1a75d2",
       "IPY_MODEL_713bf7f3026f4a1daa52df12016caf82"
      ],
      "layout": "IPY_MODEL_ae4725f43a3846acbdcbbf79f51166d0"
     }
    },
    "cbe44862bf474ff692a359314a7c21f1": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_00a38829bf664b0084b5ec704047f00d",
      "placeholder": "​",
      "style": "IPY_MODEL_f32af41f2b9543e497989b2c44e9d62d",
      "value": "Ranking by BM25...: 100%"
     }
    },
    "d58eb54b8b04455b9e506598491b5b2b": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "d5d73be36bdb4ddb8fcd92f1ae7a2856": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "d8777b76fb5341869afcb084e91231ee": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "dbdbd1d389d74c06acd9a1d3066c82dc": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "e5d659cdfd64477bbb9ce80aed7924f8": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "HTMLModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "HTMLModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "HTMLView",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_d5d73be36bdb4ddb8fcd92f1ae7a2856",
      "placeholder": "​",
      "style": "IPY_MODEL_f403167cb47840a3b0c796ae4c304401",
      "value": " 2/2 [00:00&lt;00:00, 74.12 docs/s]"
     }
    },
    "f0ff1b09bbc34065961a09ee894207bd": {
     "model_module": "@jupyter-widgets/base",
     "model_module_version": "1.2.0",
     "model_name": "LayoutModel",
     "state": {
      "_model_module": "@jupyter-widgets/base",
      "_model_module_version": "1.2.0",
      "_model_name": "LayoutModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "LayoutView",
      "align_content": null,
      "align_items": null,
      "align_self": null,
      "border": null,
      "bottom": null,
      "display": null,
      "flex": null,
      "flex_flow": null,
      "grid_area": null,
      "grid_auto_columns": null,
      "grid_auto_flow": null,
      "grid_auto_rows": null,
      "grid_column": null,
      "grid_gap": null,
      "grid_row": null,
      "grid_template_areas": null,
      "grid_template_columns": null,
      "grid_template_rows": null,
      "height": null,
      "justify_content": null,
      "justify_items": null,
      "left": null,
      "margin": null,
      "max_height": null,
      "max_width": null,
      "min_height": null,
      "min_width": null,
      "object_fit": null,
      "object_position": null,
      "order": null,
      "overflow": null,
      "overflow_x": null,
      "overflow_y": null,
      "padding": null,
      "right": null,
      "top": null,
      "visibility": null,
      "width": null
     }
    },
    "f32af41f2b9543e497989b2c44e9d62d": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "f403167cb47840a3b0c796ae4c304401": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "DescriptionStyleModel",
     "state": {
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "DescriptionStyleModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/base",
      "_view_module_version": "1.2.0",
      "_view_name": "StyleView",
      "description_width": ""
     }
    },
    "f4f835630d074a618f4389c69d1a75d2": {
     "model_module": "@jupyter-widgets/controls",
     "model_module_version": "1.5.0",
     "model_name": "FloatProgressModel",
     "state": {
      "_dom_classes": [],
      "_model_module": "@jupyter-widgets/controls",
      "_model_module_version": "1.5.0",
      "_model_name": "FloatProgressModel",
      "_view_count": null,
      "_view_module": "@jupyter-widgets/controls",
      "_view_module_version": "1.5.0",
      "_view_name": "ProgressView",
      "bar_style": "success",
      "description": "",
      "description_tooltip": null,
      "layout": "IPY_MODEL_3115ad83af834fe4b4fa12362205d98c",
      "max": 2,
      "min": 0,
      "orientation": "horizontal",
      "style": "IPY_MODEL_34c2218b0a4d4ba486530aeac007b00a",
      "value": 2
     }
    }
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
